/**
*
*  Elaborado por: Roberto Loaeza Valerio.
*                 geoAPP.
*                 26-abr-2006.
*
**/
package metodos;


import language.Language;
import dbClass.Puntos;
import ewe.filechooser.FileChooser;
import ewe.fx.Color;
import ewe.fx.Graphics;
import ewe.fx.Image;
import ewe.fx.Pen;
import ewe.fx.mImage;
import ewe.io.File;
import ewe.io.FileWriter;
import ewe.io.IOException;
import ewe.io.PrintWriter;
import ewe.ui.Control;
import ewe.ui.Editor;
import ewe.ui.Event;
import ewe.ui.EventListener;
import ewe.ui.GridTableModel;
import ewe.ui.Gui;
import ewe.ui.ImageControl;
import ewe.ui.InputStack;
import ewe.ui.MessageBox;
import ewe.ui.PenEvent;
import ewe.ui.ScrollBarPanel;
import ewe.ui.TableControl;
import ewe.ui.mChoice;
import ewe.ui.mLabel;
import ewe.util.Grid;
import ewe.util.Vector;
/**
 * Levantamiento por Poligonales
 * Metodo para calcular la poligonal topografica
 * @author Roberto Loaeza Valerio
 *
 */
public class LevantamientoPorPoligonales  extends Editor{	
	public LevantamientoPorPoligonalesAux datos[];
	public int contEstaciones;
	public double sumaAngulos;
	public double toleranciaAngular;
	public double errorAngular;
	public double errorAngularRepartido;	
	public double perimetro;
	public int rinicial = -1;
	public double area;
	public double t1;
	public double t2;
	public double t3;
	public double t4;
	public double ErrorLinealTotal=0;
	public int tolerancia;
	public boolean status = false;
	public String reporte="Error en: ";
	public InputStack isReporte = new InputStack();
	private double tx=0;

	private Language lang;
	
	/**
	 * Calcula el error angular
	 * @param suma Suma de angulos
	 * @param N Numero de angulos
	 * @return Error angular
	 */	
	private double ErrorAngular(double suma, int N){
		return suma-(180*(N-2));
	}
	/**
	 * Error angular a repartir
	 * @param ErrorAngular Error Angular
	 * @param N Numero de angulos
	 * @return Valor a repartir entre los angulos
	 */	
	private double ErrorAngularRepartido(double ErrorAngular, int N) {
		return (-1)*ErrorAngular/N;
	}
	/**
	 * Asigna los valores a esta clase
	 * @param puntos Arreglo de puntos
	 * @param N Cantidad de puntos
	 * @param initAzimut punto que contiene al azimut inicial
	 * @param toler Tolerancia a usar
	 */
	public void setValores(Puntos puntos[], int N, int initAzimut, int toler) {
		contEstaciones = N;
		perimetro =0;
		sumaAngulos =0;
		tolerancia = toler;
		datos = new LevantamientoPorPoligonalesAux[contEstaciones];
		
		rinicial = initAzimut;
		
		for(int i=0; i<this.contEstaciones; i++) {
			datos[i] =new LevantamientoPorPoligonalesAux();
			datos[i].anguloMedido = puntos[i].angulo;
			datos[i].distancia    = puntos[i].distancia;
			datos[i].azimut1		  = puntos[i].azimut1;
			datos[i].azimut2 	  = puntos[i].azimut2;
			perimetro += datos[i].distancia;
			sumaAngulos +=datos[i].anguloMedido;
			
		}
		if(datos[rinicial].azimut1==-1) {
			rinicial = -1;
		}
	}
	/**
	 * 
	 * Calcular la planilla topografica
	 *
	 */
	public void Calcular() {
        /////////
		///////// Calcula error angular y Error angular  a repartir
		/////////
		errorAngular = this.ErrorAngular(this.sumaAngulos, contEstaciones);
		errorAngularRepartido=this.ErrorAngularRepartido(errorAngular, contEstaciones);		
		
		toleranciaAngular = (1.0/60.0) * Math.sqrt(contEstaciones);
		
		
		/////////////
		///////////// Corrige los angulos 
		/////////////		
		for(int i=0; i<contEstaciones; i++)  
			datos[i].anguloCorregido=datos[i].anguloMedido+errorAngularRepartido;
	
		/////////////
		///////////// Si no existe un rumbo inicial definido, se solicita que elija uno
		/////////////		
		if(rinicial==-1) {
			String rumbos="";
			for(int i=0; i<contEstaciones; i++) {
				if(datos[i].azimut1!=-1	)
				rumbos+=(rumbos.length()>0)?"|"+String.valueOf(i+1):String.valueOf(i+1);
			}
			mChoice RInicial = new mChoice(rumbos,0);
			MessageBox meb = new MessageBox(lang.getTitulo(0),"", MessageBox.MBOK);
			//MessageBox meb = new MessageBox(lang.getTitulo(0),lang.getError(6), MessageBox.MBOK);
			meb.addLast(new mLabel(lang.getError(9)));		
			meb.addNext(new mLabel(lang.getTitulo(13)+":"));
			meb.addLast(RInicial);
						
			if(meb.execute(getFrame(), Gui.CENTER_FRAME )==MessageBox.IDOK) {
				rinicial =Integer.valueOf(RInicial.getText()).intValue();	
				rinicial--;
			}
		}
		
		///////////
		///////////  Arreglando los azimuts
		///////////
		int actual= rinicial;		
		double ang_ant=datos[actual].azimut1;		
		do {
			actual = (actual+1)==contEstaciones?0:actual+1;
			if(rinicial!=actual)
				ang_ant=datos[actual].FixAzimut1(ang_ant);
			//ang_ant=datos[actual].azimut1;			
		} while(rinicial != actual);
		
		
		//////////
		////////// Varios calculos internos
		//////////
		for(int i=0;i<contEstaciones; i++) {
			////////	 Calcula los RMC correspondientes
			datos[i].CalcularRMC();			
			////////	 Calcula los Cosenos y Senos de RMC
			datos[i].CalcularSin_CosRMC();
			////////	 Calcula las Proyecciones Calculadas
			datos[i].CalcularPC();
		}
		
		
		////////////
		//////////// Caculando ErrorX y ErrorY
		////////////
		double ErrorY=0, ErrorX=0;
		double SumaYmas=0;
		double SumaYmenos=0;
		double SumaXmas=0;
		double SumaXmenos=0;		
		for(int i=0; i<contEstaciones; i++) {
			ErrorY+=datos[i].pc_ny-datos[i].pc_sy;
			ErrorX+=datos[i].pc_ex-datos[i].pc_wx;
			SumaYmas+=datos[i].pc_ny;
			SumaYmenos+=datos[i].pc_sy;			
			SumaXmas+=datos[i].pc_ex;
			SumaXmenos+=datos[i].pc_wx;
		}
		
		//// Calculando el error lineal total
						
		ErrorLinealTotal=Math.sqrt((ErrorX)*(ErrorX) +(ErrorY)*(ErrorY) );	
		
		//////////
		////////// Calcula las 4 posibles tolerancias, segun la precision del equipo
		//////////
		t1=Math.sqrt((perimetro*(.000000011*perimetro+.00002)))+.0001*perimetro;
		t2=Math.sqrt((perimetro*(.000000045*perimetro+.00008)))+.0002*perimetro;
		t3=Math.sqrt((perimetro*(.00000018*perimetro+.0002)))+.0003*perimetro;
		t4=Math.sqrt((perimetro*(.0000004*perimetro+.0005)))+.001*perimetro;
		
		
		double KY= (-1)*(ErrorY)/(SumaYmas+SumaYmenos);
		double KX= (-1)*(ErrorX)/(SumaXmas+SumaXmenos);
		
		for(int i=0;i<contEstaciones; i++){
			//////// Calcula las correcciones para X y Y
			datos[i].CalcularCorreccionX_Y(KY, KX);
			//////// Corrige las Proyecciones Calculadas
			datos[i].CalcularPCC();
		}
		
		
		
		double ErrorY2=0, ErrorX2=0;
		for(int i=0; i<contEstaciones; i++) {
			ErrorY2+=datos[i].norte?datos[i].pc_nyc:datos[i].pc_syc;
			ErrorX2+=datos[i].este ?datos[i].pc_exc:datos[i].pc_wxc;			
		}
				
		///////////
		/////////// Se calculan las coordenadas
		///////////
		CalculaCoordenadas();
		
		///////////
		/////////// Se calcula el area
		///////////
		area = CalculaArea();
		area = area<0?area*(-1):area;
		
		
		switch(tolerancia) {
			case 1: status = this.ErrorLinealTotal< t1?true:false; tx=t1; break;
			case 2: status = this.ErrorLinealTotal< t2?true:false; tx=t2; break;
			case 3: status = this.ErrorLinealTotal< t3?true:false; tx=t3; break;
			case 4: status = this.ErrorLinealTotal< t4?true:false; tx=t4; break;			
		}
		
		
	}
	
	/**
	 * Regresa los erroes encontrados
	 * @return true/false si hay error
	 */
	public boolean getErrors() {
		if(status) {
			return false;
		}else {
			isReporte.inputLength = 5;
			isReporte.setCell(DONTSTRETCH);
			isReporte.add(new mLabel(""),lang.getError(0));
			isReporte.add(new mLabel(String.valueOf(sumaAngulos).toString()),lang.getTitulo(51)+":");						
			isReporte.add(new mLabel(String.valueOf(errorAngular).toString()),lang.getTitulo(52)+":");
			isReporte.add(new mLabel(String.valueOf(ErrorLinealTotal).toString()),lang.getTitulo(53)+":");
			
			isReporte.add(new mLabel("")," ");
			isReporte.add(new mLabel(""),lang.getTitulo(54));
			
			isReporte.add(new mLabel(String.valueOf((180*(contEstaciones-2))).toString()+"  ( = )"),lang.getTitulo(51)+":");						
			isReporte.add(new mLabel(String.valueOf(toleranciaAngular).toString()+" ( <= )"),lang.getTitulo(52)+":");
			isReporte.add(new mLabel(String.valueOf(tx).toString()+" ( <= )"),lang.getTitulo(53)+":");
			
			return true;
		}

	}
	/**
	 * Calcula el area de la poligonal
	 * @return Area
	 */
	private double CalculaArea() {
		double ar1, ar2;
		ar1=0;
		ar2=0;
		for(int i=0; i<contEstaciones; i++) {
			if(i!=(contEstaciones-1))
				ar1+=datos[i].corry*datos[i+1].corrx;
			else
				ar1+=datos[i].corry*datos[0].corrx;
			
			if(i!=(contEstaciones-1))
				ar2+=datos[i].corrx*datos[i+1].corry;
			else
				ar2+=datos[i].corrx*datos[0].corry;
		}
		ar2=ar2*(-1);		
		return (ar1+ar2)/2;
	}
	/**
	 * 
	 * Calcula las coordenadas
	 *
	 */
	private void CalculaCoordenadas() {
		int lastnegative =0;
		int actual;
		for(int i=0; i<contEstaciones; i++) {
			lastnegative=datos[i].pc_syc < 0 ?i:lastnegative;
		}
		boolean positivo = true;		
		double suma;
		while(positivo)
		{
			
			suma=0;
			actual = lastnegative;
			do {
				
				actual=(actual+1)==contEstaciones?0:actual+1;
				suma =datos[actual].pc_syc!=0?suma+datos[actual].pc_syc:suma+datos[actual].pc_nyc;
				suma=((suma<.000000001)&&(suma>-.000000001))?0:suma;
				datos[actual].corry=suma;
				if(suma <0)
					positivo=false;
	
			} while(lastnegative != actual);
			if(positivo)
				positivo=false;
			else {
				positivo=true;
				lastnegative=(lastnegative+1)==contEstaciones?0:lastnegative+1;
			}
		}
		
		for(int i=0; i<contEstaciones; i++) {
			lastnegative=datos[i].pc_wxc < 0 ?i:lastnegative;
		}		
		positivo = true;				
		while(positivo)
		{
			suma=0;
			actual = lastnegative;
			do {
				
				actual=(actual+1)==contEstaciones?0:actual+1;
				suma +=datos[actual].pc_wxc!=0?datos[actual].pc_wxc:datos[actual].pc_exc;

				
				suma=((suma<.000000001)&&(suma>-.000000001))?0:suma;
				datos[actual].corrx=suma;				
				if(suma<0)
					positivo=false;
	
			} while(lastnegative != actual);
			if(positivo)
				positivo=false;
			else {
				positivo=true;
				lastnegative=(lastnegative+1)==contEstaciones?0:lastnegative+1;
			}
		}
	}
	
	/**
	 * Muestra la tabla con los resultados del calculo de la planilla
	 * @param tolerancia Tolerancia a utilizar
	 * @return Tabla con los resultados
	 */
	public Control CargarTabla(int tolerancia) {
		GridTableModel gtm;
		TableControl t = new TableControl();
		Grid g = new Grid();			
		Vector titulosColumnaTabla = new Vector();
		Vector titulosFilaTabla = new Vector();		
		double s_pc_ny=0;
		double s_pc_sy=0;
		double s_pc_ex=0;
		double s_pc_wx=0;
		double s_pc_nyc=0;
		double s_pc_syc=0;
		double s_pc_exc=0;
		double s_pc_wxc=0;
		
		for(int i=0; i< contEstaciones; i++)
			titulosFilaTabla.add(String.valueOf(i).toString());
		titulosFilaTabla.add("");
		titulosFilaTabla.add("\u2211");
	
		
		for(int i=18; i<=40; i++)
			titulosColumnaTabla.add(lang.getTitulo(i));
		g.endRow();
        for (int row = 0; row != contEstaciones; row++){
        		g.add(String.valueOf(row),false);
        		
        	 	if(row == contEstaciones-1)
	        		g.add(String.valueOf(0),false);
	        	else
	        		g.add(String.valueOf(row+1),false);
        	 	g.add(String.valueOf(datos[row].distancia),false);
	        	g.add(String.valueOf(datos[row].anguloMedido),false);
	        	g.add(String.valueOf(datos[row].anguloCorregido),false);
	        	
	        	g.add(String.valueOf(datos[row].azimut1),false);
	        	g.add(datos[row].sRMC,false);
	        	g.add(String.valueOf(datos[row].cosenoRMC),false);
	        	g.add(String.valueOf(datos[row].senoRMC),false);
	        	
	        	g.add(String.valueOf(datos[row].pc_ny),false);	        	
	        	g.add(String.valueOf(datos[row].pc_sy),false);	        	
	        	g.add(String.valueOf(datos[row].pc_ex),false);
	        	g.add(String.valueOf(datos[row].pc_wx),false);
	        	s_pc_ny+=datos[row].pc_ny;
	        	s_pc_sy+=datos[row].pc_sy;
	        	s_pc_ex+=datos[row].pc_ex;
	        	s_pc_wx+=datos[row].pc_wx;
	        	
	        	
	        	g.add(String.valueOf(datos[row].correcy),false);
	        	g.add(String.valueOf(datos[row].correcx),false);
	        	g.add(String.valueOf(datos[row].pc_nyc),false);	        	
	        	g.add(String.valueOf(datos[row].pc_syc),false);
	        	g.add(String.valueOf(datos[row].pc_exc),false);
	        	g.add(String.valueOf(datos[row].pc_wxc),false);
	        	s_pc_nyc+=datos[row].pc_nyc;
	        	s_pc_syc+=datos[row].pc_syc;
	        	s_pc_exc+=datos[row].pc_exc;
	        	s_pc_wxc+=datos[row].pc_wxc;
	        	
	        	
	        	g.add(String.valueOf(datos[row].corry ),false);
	        	g.add(String.valueOf(datos[row].corrx ),false);
	        	if(row==0) {
	        		g.add(String.valueOf(area ),false);
	        		g.add(String.valueOf(perimetro),false);	        	        		
	        	}
            g.endRow();
        }
        g.add("",false);
        g.endRow();
        g.add("",false);
        g.add("",false);
        
        g.add(String.valueOf(perimetro),false);
        g.add(String.valueOf(sumaAngulos),false);
        g.add(String.valueOf(sumaAngulos),false);
        g.add("",false);
        g.add("",false);
        g.add("",false);
        g.add("",false);
        
        g.add(String.valueOf(s_pc_ny),false);
        g.add(String.valueOf(s_pc_sy),false);
        g.add(String.valueOf(s_pc_ex),false);
        g.add(String.valueOf(s_pc_wx),false);
        g.add("",false);
        g.add("",false);
        g.add(String.valueOf(s_pc_nyc),false);
        g.add(String.valueOf(s_pc_syc),false);
        g.add(String.valueOf(s_pc_exc),false);
        g.add(String.valueOf(s_pc_wxc),false);
        
        g.endRow();
        
        gtm = new GridTableModel();
        gtm.setDataAndHeaders(g,titulosColumnaTabla,titulosFilaTabla);        
        gtm.calculateSizes(t.getFontMetrics());
        gtm.hasPreferredSize = true;
        t.setTableModel(gtm);                      	        
        return new ScrollBarPanel(t);
	
	}
	/**
	 * Carga un croquis
	 * @param tolerancia Tolerancia a usar
	 * @param xmax valor maximo para x
	 * @param ymax valor maximo para y
	 * @param escala escala (zoom)
	 * @return Croquis del levantamiento (orientado)
	 */
	public ImageControl CargarImagen(int tolerancia, int xmax, int ymax, int escala) {		
		int x[] = new int[contEstaciones+1];
		int y[] = new int[contEstaciones+1];
		int maxx, maxy;
		xmax*=escala;
		ymax*=escala;
		
		maxx =maxy =0;		
		for(int i=0; i<contEstaciones; i++) {		
			x[i] =(int)datos[i].corrx;
			y[i] =(int)datos[i].corry;
			maxx=maxx<x[i]?x[i]:maxx;
			maxy=maxy<y[i]?y[i]:maxy;
		}
		
		for(int i=0; i<contEstaciones; i++) {
			x[i] =(x[i]+5)*2;
			y[i] =(maxy-y[i]+15)*2;			
		}
		
		maxx=(maxx+25)*2;
		maxy=(maxy+25)*2;		
		x[contEstaciones] = x[0];
		y[contEstaciones] = y[0];

		int maxV = maxx > maxy?maxx:maxy;
		int minImg = xmax < ymax?xmax:ymax;
		for(int i=0; i<contEstaciones; i++) {
			y[i]=this.regla3(maxV, minImg-80, y[i])+15;
			x[i]=this.regla3(maxV, minImg-80, x[i])+15;
		}
		x[contEstaciones] = x[0];
		y[contEstaciones] = y[0];
		final Image img = new Image(xmax,ymax);
		Graphics g = new Graphics(img);
		g.setColor(Color.White);
		g.fillRect(0,0,img.getWidth(),img.getHeight());
		g.setColor(Color.DarkGray);			
		if(status) {
			//g.setPen(new Pen(colorLinea(0,contEstaciones),Pen.SOLID,2));
			//g.drawLines(x,y, contEstaciones+1);
			for(int i=0; i<contEstaciones-1; i++) {
				g.setPen(new Pen(colorLinea(i,contEstaciones),Pen.SOLID,2));				
				g.drawLine(x[i], y[i],x[i+1],y[i+1]);				
			}
			g.setPen(new Pen(colorLinea(contEstaciones-1,contEstaciones),Pen.SOLID,2));
			g.drawLine(x[contEstaciones-1], y[contEstaciones-1],x[0],y[0]);
		}
		else {						
			//g.drawLines(x,y, contEstaciones-1);
			for(int i=0; i<contEstaciones-2; i++) {
				g.setPen(new Pen(colorLinea(i,contEstaciones),Pen.SOLID,2));
				g.drawLine(x[i], y[i],x[i+1],y[i+1]);				
			}
			g.setPen(new Pen(colorLinea(contEstaciones-1,contEstaciones),Pen.SOLID,2));
			g.drawLine(x[contEstaciones-1], y[contEstaciones-1],x[0],y[0]);
			g.setPen(new Pen(colorLinea(contEstaciones-2,contEstaciones),Pen.DASH,2));
			//g.setPen(new Pen(new Color(255,0,0),Pen.DASH,2));
			g.drawLine(x[contEstaciones-1], y[contEstaciones-1],x[contEstaciones-2], y[contEstaciones-2]);
		}
		int tam_ellipse = 10;
		for(int i=0; i<contEstaciones; i++) {
			int xy[] = new int[2];				
			if(i==0) {
				xy = posText(x[contEstaciones-1], y[contEstaciones-1], x[i], y[i], x[i+1], y[i+1]);
				//xy = posText(x[i-1], y[i-1], x[i], y[i], x[i+1], y[i+1]);
			}
			else if(i==contEstaciones-1) {
				xy = posText(x[i-1], y[i-1], x[i], y[i], x[0], y[0]);
			}
			else {
				xy = posText(x[i-1], y[i-1], x[i], y[i], x[i+1], y[i+1]);
			}
			
			if(i<contEstaciones-1) {
				
				
				//ewe.sys.Vm.debug(i+" ("+xy[0]+", "+xy[1]+")");
				//g.setColor(Color.Black);
				//g.drawText(String.valueOf(i+2).toString(),x[i]+1,y[i]);
				
				g.setColor(colorLinea(i,contEstaciones));
				g.drawText(String.valueOf(i+2).toString(),xy[0],xy[1]);
				g.drawEllipse(x[i]-3, y[i]-(tam_ellipse/2), tam_ellipse, tam_ellipse);
				g.fillEllipse(x[i]-3, y[i]-(tam_ellipse/2), tam_ellipse, tam_ellipse);
			}
			else {
				g.setColor(colorLinea(i,contEstaciones));		
				g.drawEllipse(x[i]-3, y[i]-(tam_ellipse/2), tam_ellipse, tam_ellipse);
				g.fillEllipse(x[i]-3, y[i]-(tam_ellipse/2), tam_ellipse, tam_ellipse);
				g.drawText("1",xy[0],xy[1]);
			}
		}
		
		
		
		mImage mi = new mImage();
		mi.setImage(img);
		mi.transparentColor = Color.White;		
		
		ImageControl imgC = new ImageControl(img);
		
		imgC.addListener( new EventListener() {
			public void onEvent(Event ev){
				if (ev.type == PenEvent.PEN_DOWN) {
					PenEvent p = (PenEvent)ev;										
					int pixeless[] = new int[1];
					img.getPixels(pixeless,0, p.x,p.y,1,1,1);					
					int pos = colorLinea2Posicion(pixeless[0],contEstaciones);					
					if(pos != -1) {
						pos = (pos+1)<contEstaciones?pos+1:0;
						new ewe.ui.MessageBox(lang.getTitulo(0),lang.getTitulo(15)+" = "+datos[pos].anguloMedido+(char)176+"\n"+lang.getTitulo(16)+" = "+datos[pos].distancia, ewe.ui.MessageBox.MBOK).execute(getFrame(), Gui.CENTER_FRAME);
					}
						
				}
			}
		});		
		
		return /*new ScrollBarPanel*/(imgC);		
	}
	/**
	 * Regresa la mejor posicion para el texto, es decir que no se escriba sobre otra linea.
	 * @param x_ant X en posicion anterior
	 * @param y_ant Y en posicion anterior
	 * @param x_act X en posicion actual 
	 * @param y_act Y en posicion actual 
	 * @param x_sig X en posicion siguiente
	 * @param y_sig Y en posicion siguiente
	 * @return [x][y] Nuevas posiciones para el texto (sin sobre-escribir)
	 */
	private int[]posText(int x_ant, int y_ant, int x_act, int y_act, int x_sig, int y_sig) {
		int x, y;
		x = x_act;
		y = y_act;
		int inc = 8; 			
		
		boolean c1, c2, c3, c4;
		c1 = c2 = c3 = c4=true;		
		
		/**
		 *   c1		c2
		 *       x
		 *   c4		c3
		 */
		
		if(x_ant<x_act) {	 	// (c1 | c4)
			if(y_ant<y_act) { 	// (c1 | c2)
				c1=false; 		// (c1)
			}
			else				// (c4 | c3)
				c4=false;		// (c4)
		} 
		else {					// (c2 | c3)
			if(y_ant<y_act) {	// (c1 | c2)
				c2=false;		// (c2)
			}
			else				// (c4 | c3)
				c3=false;		// (c3)
		}
		
		
		if(x_sig<x_act) {	 	// (c1 | c4)
			if(y_sig<y_act) { 	// (c1 | c2)
				c1=false; 		// (c1)
			}
			else				// (c4 | c3)
				c4=false;		// (c4)
		} 
		else {					// (c2 | c3)
			if(y_sig<y_act) {	// (c1 | c2)
				c2=false;		// (c2)
			}
			else				// (c4 | c3)
				c3=false;		// (c3)
		}
		
		
		if(c1) {
			x-=(inc*2);
			y-=(inc*2);
		} else if(c2) {
			x+=inc;
			y-=(inc*2);
		}else if(c3) {
			x+=inc;
			y+=inc;
		}else if(c4) {
			x-=(inc*2);
			y+=(inc*2);
		}		
			
		return new int[]{ x, y};
	}
	
	
	
	/**
	 * Regresa el numero de estacion a partir del color de la linea con la que se
	 * grafico.
	 * @param colorLinea Color de la linea (aRGB)
	 * @param contLinea Numero Total de estaciones(lineas)
	 * @return Numero de estacion (0  - contLinea) o (-1) caso falso 
	 */
	private int colorLinea2Posicion(int colorLinea, int contLinea) {
		int pos = -1;
		Color temp;
		for(int i=0; i<contLinea; i++) {
			temp = colorLinea(i, contLinea);
			if(temp.toInt() == colorLinea) {
				pos = i;
				break;
			}
		}			
		//new ewe.ui.MessageBox("-", "pos"+pos+" color "+colorLinea,MessageBox.OKB).execute();		
		return pos;		
	}
	/**
	 * Regresa el color para una linea en especifico, este color sirve para identificarla
	 * y mostrar sus respectivos datos.
	 * @param idLinea ID de estacion
	 * @param contLinea Numero total de estaciones
	 * @return Nuevo color (unico)
	 */
	private Color colorLinea(int idLinea, int contLinea ) {
		int R, G, B;
		R = G = B = 0;
		int max = 150;
		int mult = (max*3)/contLinea;			
		int RGB = idLinea*mult;
		
		
		R = RGB<max? RGB:max;
			RGB -= R;		
		G = RGB<max? RGB:max;
			RGB -= G;
		B = RGB<max? RGB:max;								
		return new Color(R, G, B);
	}
	
	
	/**
	 * Regla de 3 para autoajustar el croquis
	 * A -> B
	 * C -> ? (valor buscado)
	 * @param A A
	 * @param B B
	 * @param C C
	 * @return ? (El valor buscado)
	 */
	private int regla3(int A, int B, int C) {		
		return (C*B)/A;
				
	}
	/**
	 * Levantamiento por poligonales
	 * @param l Idioma
	 */
	public LevantamientoPorPoligonales(Language l){ 
		this.lang = l;			
	}
	
	
		
	private String poliLine(int total, double []x, double []y, boolean inicio, boolean fin, int conts) {
		String polilinea ="";
			
		if (inicio )
			polilinea +="\n0" +
						"\nSECTION" +
						"\n2" +
						"\nENTITIES" ;
		polilinea+="\n0" +
					"\nLWPOLYLINE" +
					"\n5" +
					"\n"+String.valueOf(conts) +
					"\n100" +
					"\nAcDbEntity" +
					"\n8" +
					"\n0" +
					"\n100" +
					"\nAcDbPolyline\n62\n3\n90\n"+String.valueOf(total)+"\n70\n0";
		for(int i= 0; i<total; i++)
		{
			polilinea +="\n10\n"+String.valueOf(x[i]) +
						"\n20\n"+String.valueOf(y[i]) ;	
		}
		if (fin) 
		polilinea+="\n0"+
					"\nAcDbEntity" +
					"\n8" +
					"\n0" +
					"\n100" +
					"\nAcDbText" +
					"\n  0" +
					"\nENDSEC" ;					
		return polilinea;
	}
	
	private String texto(double x, double y, String txt, double tam, int conts) {
		String tex="\n0\nMTEXT" +
				"\n5" +
				"\n"+String.valueOf(conts) +
				"\n100" +
				"\nAcDbEntity" +
				"\n100" +
				"\nAcDbMText" +
				"\n8" +
				"\n0" +
				"\n62" +
				"\n4" +
				"\n370" +
				"\n-1" +
				"\n6" +
				"\nByLayer" +
				"\n10" +
				"\n" +String.valueOf(x)+
				"\n20" +
				"\n"+String.valueOf(y) +
				"\n30" +
				"\n0.0" +
				"\n40" +
				"\n"+String.valueOf(tam) +
				"\n41" +
				"\n100.0" +
				"\n71" +
				"\n7" +
				"\n72" +
				"\n2" +
				"\n1" +
				"\n"+txt+
				"\n7" +
				"\nStandard" +
				"\n50" +
				"\n0.0" +
				"\n73" +
				"\n0" +
				"\n44" +
				"\n1.0";
		return tex;
	}
	
	
	/**
	 * Exportar a DXF
	 * @param levantamiento Proyecto a exportar
	 * @return true/false
	 * @throws IOException
	 */
	public boolean DXF(dbClass.Levantamientos levantamiento) throws IOException
	{					
		FileChooser fc =new FileChooser(FileChooser.SAVE,levantamiento.nombre+".dxf");
		fc.mask = levantamiento.nombre+".dxf";						
		
		if( fc.execute() != FileChooser.IDCANCEL ){
			File f = fc.getChosenFile();			
			FileWriter archivo =new FileWriter(f);
			PrintWriter salida = new PrintWriter(archivo);
			int contE = this.contEstaciones +1;
			double maxx=0;
			double maxy=0;
			int Contador=30;
			double x[] = new double[contE];
			double y[] = new double[contE];
			for (int row = 0; row != contE-1; row++){
				x[row] = datos[row].corrx;
				y[row] = datos[row].corry;
				maxx = maxx< x[row] ? x[row]: maxx;
				maxy = maxy< y[row] ? y[row]: maxy;
			
			}
			x[contE-1] = datos[0].corrx;
			y[contE-1] = datos[0].corry;			
			
			
			maxx+=150;
			maxy+=30;
			
			
			salida.write(this.cabecera);
			salida.write(this.poliLine(7,new double[] {-10,maxx,maxx,maxx-35,maxx-35,-10,-10}, new double[]{-10,-10,maxy-30,maxy-30,maxy,maxy,-10}, true, false, Contador++ )); //marco								
			salida.write(this.poliLine(5,new double[] {maxx-33,maxx,maxx,maxx-33,maxx-33}, new double[]{maxy-28,maxy-28,maxy,maxy,maxy-28}, false, false, Contador++)); //rec norte								
			salida.write(this.poliLine(5,new double[] {maxx-17.5, maxx-27.5, maxx-17.5, maxx-7.5, maxx-17.5}, new double[]{maxy-2,maxy-17,maxy-13, maxy-17, maxy-2}, false, false, Contador++)); //norte						
			salida.write(this.texto(maxx-18,maxy-25,"N",5,Contador++));
			
			
			
			salida.write(this.poliLine(5,new double[] {maxx, maxx-82, maxx-82, maxx, maxx}, new double[]{-10,-10,37, 37, -10}, false, false, Contador++));  //datos
			salida.write(this.texto(maxx-77,30,lang.getTitulo(44),1,Contador++));
			salida.write(this.texto(maxx-74,26,levantamiento.nombre,3,Contador++));
			salida.write(this.texto(maxx-77,22,lang.getTitulo(45),1,Contador++));
			salida.write(this.texto(maxx-74,18,levantamiento.propietario,2,Contador++));
			salida.write(this.texto(maxx-77,14,lang.getTitulo(46),1,Contador++));
			salida.write(this.texto(maxx-74,10,levantamiento.ubicacion,2,Contador++));
			salida.write(this.texto(maxx-77,6,lang.getTitulo(47),1,Contador++));
			salida.write(this.texto(maxx-74,2,levantamiento.levanto,2,Contador++));
			salida.write(this.texto(maxx-77,-2,lang.getTitulo(48),1,Contador++));
			salida.write(this.texto(maxx-74,-6,levantamiento.reviso,2,Contador++));
			
			
			salida.write(this.poliLine(5,new double[] {maxx-92, maxx-5, maxx-5, maxx-92, maxx-92}, new double[]{maxy-39,maxy-39,maxy-(45+(contE-1)*3), maxy-(45+(contE-1)*3), maxy-39}, false, false, Contador++)); //construccion
			salida.write(this.poliLine(2,new double[] {maxx-92, maxx-80}, new double[]{maxy-42,maxy-42}, false, false, Contador++)); //construccion
			salida.write(this.poliLine(2,new double[] {maxx-86, maxx-86}, new double[]{maxy-42,maxy-(45+(contE-1)*3)}, false, false, Contador++)); //divi e | pv				
			salida.write(this.poliLine(2,new double[] {maxx-80, maxx-80}, new double[]{maxy-(45+(contE-1)*3),maxy-39}, false, false, Contador++)); // div lados | dist
			salida.write(this.poliLine(2,new double[] {maxx-67, maxx-67}, new double[]{maxy-(45+(contE-1)*3),maxy-39}, false, false, Contador++)); //div dist |rmc
			salida.write(this.poliLine(2,new double[] {maxx-48, maxx-48}, new double[]{maxy-(45+(contE-1)*3),maxy-39}, false, false, Contador++)); //div rmc | v
			salida.write(this.poliLine(2,new double[] {maxx-42, maxx-42}, new double[]{maxy-(45+(contE-1)*3),maxy-39}, false, false, Contador++)); //div v | coor x
			salida.write(this.poliLine(2,new double[] {maxx-23.5, maxx-23.5}, new double[]{maxy-42,maxy-(45+(contE-1)*3)}, false, false, 23)); //divi x | y
			salida.write(this.poliLine(2,new double[] {maxx-92, maxx-5}, new double[]{maxy-(45),maxy-(45)}, false, false, Contador++)); //construccion
			salida.write(this.poliLine(2,new double[] {maxx-42, maxx-5}, new double[]{maxy-42,maxy-42}, false, false, Contador++)); //construccion
		
			for(int i=1; i<contE; i++)
			{
				salida.write(this.poliLine(2,new double[] {maxx-92, maxx-5}, new double[]{maxy-(45+(i*3)),maxy-(45+(i*3))}, false, false, Contador++)); //construccion
				
				salida.write(this.texto(maxx-91,maxy-(44.5+(i*3)),String.valueOf(i),2,Contador++));  //e
				if(i==contE-1)
				{
					salida.write(this.texto(maxx-84.5,maxy-(44.5+(i*3)),String.valueOf(1),2,Contador++));	//pv
					salida.write(this.texto(maxx-47,maxy-(44.5+(i*3)),String.valueOf(1),2,Contador++)); //v
				}
				else
				{
					salida.write(this.texto(maxx-84.5,maxy-(44.5+(i*3)),String.valueOf(i+1),2,Contador++));	//pv
					salida.write(this.texto(maxx-47,maxy-(44.5+(i*3)),String.valueOf(i+1),2,Contador++)); //v
				}
				salida.write(this.texto(maxx-77,maxy-(44.5+(i*3)),String.valueOf(datos[i-1].distancia),2,Contador++));  //dist
				salida.write(this.texto(maxx-64,maxy-(44.5+(i*3)),datos[i-1].sRMC,2,Contador++));  //rmc
									
				double x2=((int)(datos[i-1].corrx*1000));
				double y2=((int)(datos[i-1].corry*1000));
				salida.write(this.texto(maxx-39,maxy-(44.5+(i*3)),String.valueOf(y2/1000),2,Contador++));  //y
				salida.write(this.texto(maxx-20.5,maxy-(44.5+(i*3)),String.valueOf(x2/1000),2,Contador++));  //x
				
				
			}
				
			
			salida.write(this.texto(maxx-89.5,maxy-41.5,lang.getTitulo(49),2,Contador++));
			salida.write(this.texto(maxx-77,maxy-41.5,lang.getTitulo(20),2,Contador++));
			salida.write(this.texto(maxx-77,maxy-44.5,lang.getTitulo(50),2,Contador++));
			salida.write(this.texto(maxx-60,maxy-43,lang.getTitulo(24),2,Contador++));
			salida.write(this.texto(maxx-47,maxy-43,lang.getTitulo(43),2,Contador++));
			
			salida.write(this.texto(maxx-37,maxy-41.5,lang.getTitulo(42),2,Contador++));
			salida.write(this.texto(maxx-89.5,maxy-44.5,lang.getTitulo(18),2,Contador++));
			salida.write(this.texto(maxx-85.5,maxy-44.5,lang.getTitulo(19),2,Contador++));				
			salida.write(this.texto(maxx-36,maxy-44.5,lang.getTitulo(37),2,Contador++));
			salida.write(this.texto(maxx-17.5,maxy-44.5,lang.getTitulo(38),2,Contador++));

			
			
			for(int i=0; i!= (contE-1) ; i++)
			{					
				if((i<(contE-2))&&(i>0))
					if(y[i]>y[i-1])
						if(x[i+1]>x[i])
							salida.write(this.texto(x[i]-4,y[i]+4,String.valueOf(i+2).toString(),3,Contador++));
						else
							salida.write(this.texto(x[i]+4,y[i]+4,String.valueOf(i+2).toString(),3,Contador++));
					else
						if(x[i+1]>x[i])
							salida.write(this.texto(x[i]-4,y[i]-4,String.valueOf(i+2).toString(),3,Contador++));
						else
							salida.write(this.texto(x[i]+4,y[i]-4,String.valueOf(i+2).toString(),3,Contador++));
				else
					if(i>0)
						salida.write(this.texto(x[i]+4,y[i]+4,String.valueOf(1).toString(),3,Contador++));
					else
						salida.write(this.texto(x[i]+4,y[i]+4,String.valueOf(i+2).toString(),3,Contador++));
			}

			salida.write(this.poliLine((contE),x,y,false, true, Contador++)); //poligonal				
			salida.write(this.restostr);
			salida.close();											        						
		}
		else {
			return false;			
		}		
		return true;
	}
	private String cabecera= "0"+
	"\nSECTION" +
	"\n  2" +
	"\nHEADER" +
	"\n9" +
	"\n$ACADVER" +
	"\n1" +
	"\nAC1014" +
	"\n9" +
	"\n$HANDSEED" +
	"\n5" +
	"\n27" +
	"\n9" +
	"\n$INSUNITS" +
	"\n70" +
	"\n4" +
	"\n9" +		
	"\n$LIMMIN" +
	"\n10" +
	"\n-15.0" + //limite X minimo
	"\n20" +
	"\n-15.0" + //limite Y minimo
	"\n9" +
	"\n$LIMMAX" +
	"\n10" +
	"\n280.0" + //limite X maximo
	"\n20" +
	"\n150.0" + //limite Y maximo
	"\n  0" +
	"\nENDSEC" +
	"\n  0" +
	"\nSECTION" +
	"\n  2" +
	"\nTABLES" +
	"\n  0" +
	"\nTABLE" +
	"\n  2" +
	"\nVPORT" +
	"\n  5" +
	"\n  1" +
	"\n100" +
	"\nAcDbSymbolTable" +
	"\n  0" +
	"\nENDTAB" +
	"\n  0" +
	"\nTABLE" +
	"\n  2" +
	"\nLTYPE" +
	"\n  5" +
	"\n  2" +
	"\n100" +
	"\nAcDbSymbolTable" +
	"\n  0" +
	"\nLTYPE" +
	"\n  5" +
	"\n  3" +
	"\n100" +
	"\nAcDbSymbolTableRecord" +
	"\n100" +
	"\nAcDbLinetypeTableRecord" +
	"\n  2" +
	"\nBYBLOCK" +
	"\n 70" +
	"\n     0" +
	"\n 0" +
	"\nLTYPE" +
	"\n  5" +
	"\n  4" +
	"\n100" +
	"\nAcDbSymbolTableRecord" +
	"\n100" +
	"\nAcDbLinetypeTableRecord" +
	"\n  2" +
	"\nBYLAYER" +
	"\n 70" +
	"\n     0" +
	"\n  0" +
	"\nENDTAB" +
	"\n0" +
	"\nTABLE" +
	"\n  2" +
	"\nLAYER" +
	"\n  5" +
	"\n 1A" +
	"\n330" +
	"\n  0" +
	"\n100" +
	"\nAcDbSymbolTable" +
	"\n0" +
	"\nLAYER" +
	"\n5" +
	"\n24" +
	"\n330" +
	"\n 1A" +
	"\n100" +
	"\nAcDbSymbolTableRecord" +
	"\n100" +
	"\nAcDbLayerTableRecord" +
	"\n2" +
	"\n0" +
	"\n70" +
	"\n0" +
	"\n62" +
	"\n7" +
	"\n6" +
	"\nContinuous" +
	"\n  0" +
	"\nENDTAB" +
	"\n  0" +
	"\nTABLE" +
	"\n  2" +
	"\nSTYLE" +
	"\n  5" +
	"\n  5" +
	"\n100" +
	"\nAcDbSymbolTable" +
	"\n  0" +
	"\nSTYLE" +
	"\n  5" +
	"\n  6" +
	"\n100" +
	"\nAcDbSymbolTableRecord" +
	"\n100" +
	"\nAcDbTextStyleTableRecord" +
	"\n  2" +
	"\nSTANDARD" +
	"\n 70" +
	"\n     0" +
	"\n 40" +
	"\n0.0" +
	"\n 41" +
	"\n1.0" +
	"\n 50" +
	"\n0.0" +
	"\n 71" +
	"\n     0" +
	"\n 42" +
	"\n10.0" +
	"\n  3" +
	"\ntxt" +
	"\n  4" +
	"\nbigfont" +
	"\n  0" +
	"\nENDTAB" +
	"\n0" +
	"\nTABLE" +
	"\n  2" +
	"\nVIEW" +
	"\n  5" +
	"\n  7" +
	"\n100" +
	"\nAcDbSymbolTable" +
	"\n  0" +
	"\nENDTAB" +
	"\n  0" +
	"\nTABLE" +
	"\n  2" +
	"\nUCS" +
	"\n  5" +
	"\n  8" +
	"\n100" +
	"\nAcDbSymbolTable" +
	"\n  0" +
	"\nENDTAB" +
	"\n  0" +
	"\nTABLE" +
	"\n  2" +
	"\nAPPID" +
	"\n  5" +
	"\n  9" +
	"\n100" +
	"\nAcDbSymbolTable" +
	"\n  0" +
	"\nAPPID" +
	"\n  5" +
	"\n  A" +
	"\n100" +
	"\nAcDbSymbolTableRecord" +
	"\n100" +
	"\nAcDbRegAppTableRecord" +
	"\n  2" +
	"\nACAD" +
	"\n 70" +
	"\n0" +
	"\n  0" +
	"\nENDTAB" +
	"\n  0" +
	"\nTABLE" +
	"\n  2" +
	"\nDIMSTYLE" +
	"\n  5" +
	"\n  B" +
	"\n100" +
	"\nAcDbSymbolTable" +
	"\n  0" +
	"\nENDTAB" +
	"\n  0" +
	"\nTABLE" +
	"\n  2" +
	"\nBLOCK_RECORD" +
	"\n  5" +
	"\n  C" +
	"\n100" +
	"\nAcDbSymbolTable" +
	"\n0" +
	"\nBLOCK_RECORD" +
	"\n5" +
	"\n  D" +
	"\n100" +
	"\nAcDbSymbolTableRecord" +
	"\n100" +
	"\nAcDbBlockTableRecord" +
	"\n  2" +
	"\n*MODEL_SPACE" +
	"\n  0" +
	"\nBLOCK_RECORD" +
	"\n  5" +
	"\n  E" +
	"\n100" +
	"\nAcDbSymbolTableRecord" +
	"\n100" +
	"\nAcDbBlockTableRecord" +
	"\n  2" +
	"\n*PAPER_SPACE" +
	"\n  0" +
	"\nENDTAB" +
	"\n  0" +
	"\nENDSEC" +
	"\n  0" +
	"\nSECTION" +
	"\n  2" +
	"\nBLOCKS" +
	"\n  0" +
	"\nBLOCK" +
	"\n  5" +
	"\n  F" +
	"\n330" +
	"\n  D" +
	"\n100" +
	"\nAcDbEntity" +
	"\n  8" +
	"\n0" +
	"\n100" +
	"\nAcDbBlockBegin" +
	"\n  2" +
	"\n*MODEL_SPACE" +
	"\n 70" +
	"\n     0" +
	"\n  0" +
	"\nENDBLK" +
	"\n5" +
	"\n10" +
	"\n100" +
	"\nAcDbEntity" +
	"\n8" +
	"\n0" +
	"\n100" +
	"\nAcDbBlockEnd" +
	"\n0" +
	"\nBLOCK" +
	"\n5" +
	"\n11" +
	"\n330" +
	"\n  E" +
	"\n100" +
	"\nAcDbEntity" +
	"\n  8" +
	"\n0" +
	"\n100" +
	"\nAcDbBlockBegin" +
	"\n  2" +
	"\n*PAPER_SPACE" +
	"\n70" +
	"\n0" +
	"\n0" +
	"\nENDBLK" +
	"\n5" +
	"\n12" +
	"\n100" +
	"\nAcDbEntity" +
	"\n8" +
	"\n0" +
	"\n100" +
	"\nAcDbBlockEnd" +
	"\n0" +
	"\nENDSEC";
	
	
	private String restostr =	"\n  0" +
	"\nSECTION" +
	"\n  2" +
	"\nOBJECTS" +
	"\n  0" +
	"\nDICTIONARY" +
	"\n  5" +
	"\n13" +
	"\n100" +
	"\nAcDbDictionary" +
	"\n  3" +
	"\nACAD_GROUP" +
	"\n350" +
	"\n14" +
	"\n  3" +
	"\nACAD_MLINESTYLE" +
	"\n350" +
	"\n15" +
	"\n  0" +
	"\nDICTIONARY" +
	"\n  5" +
	"\n14" +
	"\n102" +
	"\n{ACAD_REACTORS" +
	"	\n330" +
	"	\n13" +
	"	\n102" +
	"	\n}" +
	"\n100" +
	"\nAcDbDictionary" +
	"\n  0" +
	"\nDICTIONARY" +
	"\n  5" +
	"\n15" +
	"\n102" +
	"\n{ACAD_REACTORS" +
	"	\n330" +
	"	\n13" +
	"	\n102" +
	"	\n}" +
	"\n100" +
	"\nAcDbDictionary" +
	"\n3" +
	"" +
	"\nSTANDARD" +
	"\n350" +
	"\n16" +
	"\n  0" +
	"\nMLINESTYLE" +
	"\n  5" +
	"\n16" +
	"\n102" +
	"\n{ACAD_REACTORS" +
	"	\n330" +
	"	\n15" +
	"	\n102" +
	"	\n}" +
	"\n100" +
	"\nAcDbMlineStyle" +
	"\n  2" +
	"\nSTANDARD" +
	"\n 70" +
	"\n0" +
	"\n  3" +
	"\n" +
	"" +
	"\n62" +
	"\n256" +
	"\n51" +
	"\n90.0" +
	"\n52" +
	"\n90.0" +
	"\n 71" +
	"\n2" +
	"\n49" +
	"\n0.5" +
	"\n62" +
	"\n   256" +
	"\n  6" +
	"\nBYLAYER" +
	"\n 49" +
	"\n-0.5" +
	"\n 62" +
	"\n256" +
	"\n  6" +
	"\nBYLAYER" +
	"\n  0" +
	"\nENDSEC" +
	"\n  0" +
	"\nEOF" ;		

}
